#pragma once 

#include "vector3.h"
#include "vector2.h"
#include "colorvalue.h"
#include "RenderUtils.h"
#include "matrix4.h"

namespace RenderSystem
{
	class FPrimitiveDrawInterface;



	/** The vertex type used for dynamic meshes. */
	struct FDynamicMeshVertex
	{
		FDynamicMeshVertex() {}
		FDynamicMeshVertex( const Common::Vector3& InPosition ):
		Position(InPosition),
			TextureCoordinate(Common::Vector2(0,0)),
			TangentX(Common::Vector3(1,0,0)),
			TangentZ(Common::Vector3(0,0,1)),
			Color(Common::FColor(255,255,255)) 
		{
			// basis determinant default to +1.0
			TangentZ.Vector.W = 255;
		}

		FDynamicMeshVertex(const Common::Vector3& InPosition,const Common::Vector3& InTangentX,const Common::Vector3& InTangentZ,const Common::Vector2& InTexCoord, const FColor& InColor):
		Position(InPosition),
			TextureCoordinate(InTexCoord),
			TangentX(InTangentX),
			TangentZ(InTangentZ),
			Color(InColor)
		{
			// basis determinant default to +1.0
			TangentZ.Vector.W = 255;
		}

		void SetTangents( const Common::Vector3& InTangentX, const Common::Vector3& InTangentY, const Common::Vector3& InTangentZ )
		{
			TangentX = InTangentX;
			TangentZ = InTangentZ;
			// store determinant of basis in w component of normal vector
			TangentZ.Vector.W = GetBasisDeterminantSign(InTangentX,InTangentY,InTangentZ) < 0.0f ? 0 : 255;
		}

		Common::Vector3 GetTangentY()
		{
			return (Common::Vector3(TangentZ) ^ Common::Vector3(TangentX)) * ((FLOAT)TangentZ.Vector.W / 127.5f - 1.0f);
		};

		Common::Vector3 Position;
		Common::Vector2 TextureCoordinate;
		FPackedNormal TangentX;
		FPackedNormal TangentZ;
		FColor Color;
	};

	/**
	* A utility used to construct dynamically generated meshes, and render them to a FPrimitiveDrawInterface.
	* Note: This is meant to be easy to use, not fast.  It moves the data around more than necessary, and requires dynamically allocating RHI
	* resources.  Exercise caution.
	*/
	class FDynamicMeshBuilder
	{
	public:

		/** Initialization constructor. */
		FDynamicMeshBuilder();

		/** Destructor. */
		~FDynamicMeshBuilder();

		/** Adds a vertex to the mesh. */
		INT AddVertex(
			const Common::Vector3& InPosition,
			const Common::Vector2& InTextureCoordinate,
			const Common::Vector3& InTangentX,
			const Common::Vector3& InTangentY,
			const Common::Vector3& InTangentZ,
			const FColor& InColor
			);

		/** Adds a vertex to the mesh. */
		INT AddVertex(const FDynamicMeshVertex &InVertex);

		/** Adds a triangle to the mesh. */
		void AddTriangle(INT V0,INT V1,INT V2);

		/** Adds many vertices to the mesh. */
		INT AddVertices(const std::vector<FDynamicMeshVertex> &InVertices);

		/** Add many indices to the mesh. */
		void AddTriangles(const std::vector<INT> &InIndices);

		/**
		* Draws the mesh to the given primitive draw interface.
		* @param PDI - The primitive draw interface to draw the mesh on.
		* @param LocalToWorld - The local to world transform to apply to the vertices of the mesh.
		* @param FMaterialRenderProxy - The material instance to render on the mesh.
		* @param DepthPriorityGroup - The depth priority group to render the mesh in.
		* @param DepthBias - The depth bias to render the mesh with.
		*/
		void Draw(FPrimitiveDrawInterface* PDI,const Common::Matrix4& LocalToWorld,const FMaterialRenderProxy* MaterialRenderProxy,BYTE DepthPriorityGroup,FLOAT DepthBias);

	private:
		class FDynamicMeshIndexBuffer* IndexBuffer;
		class FDynamicMeshVertexBuffer* VertexBuffer;
	};

}